﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class SteeringWheel : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{

    [System.Serializable] public class SteeringEvent : UnityEvent<float> { }
    public float maxAngle = 90; //Handle 移动最大半径

    public SteeringEvent OnValueChanged = new SteeringEvent(); //事件
    [SerializeField] private RectTransform backGround; //摇杆背景、摇杆手柄、方向指引
    private float joysticValue = 0;
    public float Value => joysticValue;
    public bool IsDraging { get; private set; }
    private int touchId = -1;
    private Vector2 startPointerPos = Vector3.zero;
    private float targetAngle = 0;

    private int _dragDirection = 0;

    public void OnDrag(PointerEventData eventData)
    {
        if (touchId != eventData.pointerId) return;
        Vector2 backGroundPos;
        backGroundPos = this.transform.position;

        Vector2 direction = eventData.position - startPointerPos; //得到偏移的指向坐标
        float distance = Vector3.Magnitude(new Vector2(direction.x * 0.5f, direction.y)); //获取向量的长度
        float offsetStartX = startPointerPos.x - backGroundPos.x;
        bool isRight = offsetStartX > 0;

        //点击摇杆偏左右的位置才生效
        if (Mathf.Abs(offsetStartX) > 20)
        {
            //起始角度
            Vector2 startDirection = startPointerPos - backGroundPos;
            //偏转角度
            Vector2 endDirection = eventData.position - backGroundPos;

            float angle = Vector2.SignedAngle(startDirection, endDirection);
            float maxAngle = this.maxAngle - 0.1f;

            //标记起始拖拽的顺逆时针方向
            if (_dragDirection == 0 && angle != 0)
            {
                _dragDirection = angle > 0 ? 1 : -1;
            }

            if (angle > maxAngle)
            {
                angle = maxAngle;
            }
            else if (angle < -maxAngle)
            {
                angle = -maxAngle;
            }

            //角度经过0，则清空方向标记
            if (Mathf.Abs(angle) < 2)
            {
                _dragDirection = 0;
            }

            //避免角度从-90 跳转到90 的情况
            if (_dragDirection != 0 && angle * _dragDirection < 0)
            {
                return;
            }

            targetAngle = angle;
            backGround.localEulerAngles = new Vector3(0, 0, targetAngle);

        }



    }

    public void OnPointerDown(PointerEventData eventData)
    {
        if (touchId != -1) return;
        startPointerPos = eventData.position;
        touchId = eventData.pointerId;
        IsDraging = true;
    }


    public void OnPointerUp(PointerEventData eventData)
    {
        if (touchId != eventData.pointerId) return;
        touchId = -1;
        targetAngle = 0;
        _dragDirection = 0;
        IsDraging = false;
    }

    private void OnJoystickCancel()
    {
        touchId = -1;
        targetAngle = 0;
        _dragDirection = 0;
        IsDraging = false;
    }

    public static bool GetTouchByFingerId(int fingerId, out Touch touch)
    {
        touch = default(Touch);
        if (Input.touchCount == 0 || fingerId < 0)
        {
            return false;
        }
        for (int i = 0; i < Input.touchCount; i++)
        {
            if (Input.GetTouch(i).fingerId == fingerId)
            {
                touch = Input.GetTouch(i);
                return true;
            }
        }

        return false;
    }

    private Touch _touch;
    private float _targetAngle = 0;
    // Update is called once per frame
    void Update()
    {
        _targetAngle = Mathf.LerpAngle(_targetAngle, targetAngle, Time.deltaTime * 5f);
        backGround.localEulerAngles = new Vector3(0, 0, _targetAngle);

        if (IsDraging)
        {
            if (touchId != -1)
            {
                if (GetTouchByFingerId(touchId, out _touch))
                {
                    switch (_touch.phase)
                    {
                        case TouchPhase.Ended:
                        case TouchPhase.Canceled:
                            OnJoystickCancel();
                            return;
                    }
                }
                else
                {
                    OnJoystickCancel();
                }
            }
            joysticValue = Mathf.Clamp(-targetAngle / maxAngle, -1f, 1f);
            OnValueChanged.Invoke(joysticValue);
        }

    }


}
